#include "raster.h"
#include "raster-gdi.h"
#include "raster-io.h"
#include "raster-fixed.h"
#include "raster-fixed-math.h"
#include "raster-3d.h"

#include <stdio.h>
#include <math.h>

#define CLASSNAME L"MainWindowClass"
#define EXSTYLE WS_EX_OVERLAPPEDWINDOW
#define STYLE WS_OVERLAPPEDWINDOW
int running = 1;
RasterRect mouseRect = { 0, 0, 100, 100 };

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_DESTROY:
        running = 0;
        break;
    case WM_MOUSEMOVE:
        mouseRect.x = (short)LOWORD((lParam)) - 50;
        mouseRect.y = (short)HIWORD((lParam)) - 50;
        break;
    }
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

HWND CreateSimpleWindowW(LPCWSTR szTitle, int x, int y, int w, int h)
{
    WNDCLASSEXW wndclass;
    RECT rc = {0, 0, w, h};

    if(!GetClassInfoExW(0, CLASSNAME, &wndclass))
    {
        wndclass.cbSize = sizeof(WNDCLASSEXW);
        wndclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
        wndclass.lpfnWndProc = &WindowProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = NULL;
        wndclass.hIcon = NULL;
        wndclass.hCursor = NULL;
        wndclass.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
        wndclass.lpszMenuName = NULL;
        wndclass.lpszClassName = CLASSNAME;
        wndclass.hIconSm = NULL;
        RegisterClassExW(&wndclass);
    }

    AdjustWindowRectEx(&rc, STYLE, 0, EXSTYLE);
    return CreateWindowExW(EXSTYLE, CLASSNAME, szTitle, STYLE, x, y, rc.right - rc.left, rc.bottom - rc.top,
                           NULL, NULL, NULL, NULL);
}

Raster *r3d = NULL;

void DrawScene(Raster *framebuffer)
{
    static int zscale = 0;
    RasterVert verts0[3];
    RasterVert verts1[3];
    BlitMode triTexMode;
    triTexMode.modes = BLIT_NORMAL;
    triTexMode.interpolation = BLIT_INTERPOLATE_BILINEAR;
    triTexMode.perspective_correction = 1;
    if(r3d == NULL)
        r3d = RasterFromFile("numbered.bmp");
    if(r3d == NULL)
        abort();
    verts0[0] = VertFromPos(100, 260);
    verts0[1] = VertFromPos(99, 390);
    verts0[2] = VertFromPos(149, 390);
    R3D_TriangleCCW(framebuffer, verts0, 0x7FFFFF00);

    verts1[0] = VertFromPosTex(300, 0, 31, 31);
    verts1[1] = VertFromPosTex(100, 100, 0, 31);
    verts1[2] = VertFromPosTex(540, 100, 0, 0);
    verts1[0].z = FIXED_ONE + IntToFixed((zscale >> 6)&0x3);
    verts1[2].z = FIXED_ONE + IntToFixed(((zscale & 0x100) >> 8));
    verts1[1].z = FIXED_HALF;
    R3D_TriangleTexCCW(framebuffer, r3d, verts1, &triTexMode);
    //zscale++;
}

int main(int argc, char **argv)
{
    HWND hwnd;
    HDC hDC;
    Raster *framebuffer, *raster, *raster2;
    BlitMode mode, mode2, mode3;
    LARGE_INTEGER perfct, perfbs, perffq;
    RasterRect spriteRect = {0, 0, 32, 32 };
    RasterRect stretchTargetRect = {50, 100, 48, 48};

    RasterPos spritePos2 = { 32, 0 };
    RasterPos spritePos = { 0, 0 };

    RasterPos linept1 = { 250, -2 };
    RasterPos linept2 = { 5, 100 };

    RasterPos triPts1[3] = {{30, 30}, {60, 10}, {0, 0}};
    RasterPos triPts2[3] = {{100, 50}, {50, 100}, {100, 75}};

    RasterPos triPts3[3] = {{200, 100}, {100, 150}, {100, 125}};
    RasterPos triPts4[3] = {{150, 480}, {200, 300}, {150, 300}};
    RasterPos triUVpts[3] = {{0, 31}, {31, 31}, {31, 0}};

    RasterPos quadPts[4] = {{100, 110}, {110, 158}, {158, 148}, {148, 100}};
    RasterPos quadUVpts[4] = {{0, 0}, {0, 31}, {31, 31}, {31, 0}};

    RasterRect clipRect = {40, 40, 120, 440 };
    RasterRect targetRect = { 0, 0, 640, 480 };
    RasterRect frameRect = { 0, 0, 640, 480 };
    int frames = 0;

    hwnd = CreateSimpleWindowW(L"Test", 55, 55, 640, 480);
    hDC = GetDC(hwnd);
    framebuffer = CreateGDITarget(hDC, FORMAT_TARGET_ALPHA, 640, 480);
    raster = RasterFromFile("cloud.bmp");
    raster2 = RasterFromFile("checkers.bmp");
    mode.modes = BLIT_COLORKEY;
    mode.colorkey = 0xFFFF00FF;
    mode.interpolation = BLIT_INTERPOLATE_BILINEAR;
    mode2.modes = BLIT_COLORMOD;
    mode2.mod.color.wht = 0xFF000000;
    mode2.mod.color.blk = 0xFF00AFAF;
    mode2.interpolation = BLIT_INTERPOLATE_BILINEAR;
    mode3.modes = BLIT_OPAQUE;
    mode3.interpolation = BLIT_INTERPOLATE_BILINEAR;
    ShowWindow(hwnd, SW_SHOWDEFAULT);

    QueryPerformanceFrequency(&perffq);
    QueryPerformanceCounter(&perfbs);
    Fixed a = -FIXED_QUARTER;
    printf("%.8x\n", FIXED_ONE << 15);
    for(; a != -FIXED_ONE; a-=0x800)
    {
        printf("%.8x %.8x\n", FixedDiv(FIXED_ONE, a), FixedInvLoss1(a));//(0x80000000 / a) << 1);
        //getchar();
    }
    a = FIXED_QUARTER;
    for(; a != FIXED_ONE; a+=0x800)
    {
        printf("%.8x %.8x\n", FixedDiv(FIXED_ONE, a), FixedInvLoss1(a));//(0x80000000 / a) << 1);
        //getchar();
    }

    //RasterSetClipRect(framebuffer, &clipRect);
    while(running)
    {
        MSG msg;
        int i = 0;
        while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }

        RasterClear(framebuffer, 0xFF7EC0EE);
        RasterBlit(framebuffer, &spritePos, raster2, &spriteRect, &mode);

        RasterBlit(framebuffer, &spritePos2, raster2, &spriteRect, &mode2);

        RasterFillRect(framebuffer, 0x7fff0000, &mouseRect);
        RasterDrawLine(framebuffer, 0xFFFFFFFF, &linept1, &linept2);

        RasterDrawTriangle(framebuffer, 0xFF7F7F7F, triPts1);
        RasterDrawTriangle(framebuffer, 0xFF7F7F7F, triPts2);
        RasterDrawTriangle(framebuffer, 0xFF7F7F7F, triPts3);
        RasterDrawTriangle(framebuffer, 0xFF7F7F7F, triPts4);


        RasterStretchBlit(framebuffer, &stretchTargetRect, raster, &spriteRect, &mode);
        RasterQuadBlit(framebuffer, quadPts, raster2, quadUVpts, &mode);
        RasterTriangleBlit(framebuffer, triPts4, raster2, triUVpts, &mode3);
//while(i != 1000)
        {

        DrawScene(framebuffer);

++i;
        }

        GdiBlitRaster(hDC, &targetRect, framebuffer, &frameRect);

        QueryPerformanceCounter(&perfct);
        ++frames;
        if(perfct.QuadPart - perfbs.QuadPart > perffq.QuadPart)
        {
            perfbs = perfct;
            printf("fps: %d\n", frames);
            frames = 0;
        }
        Sleep(0);/*  limit cpu */
    }
    DestroyRaster(raster);
    DestroyGDITarget(framebuffer);

    return 0;
}
